﻿/*
 * ©2009-2010 XELF
 * http://xelf.info
 */

#if XNA || WINDOWS_PHONE
using Microsoft.Xna.Framework;
#endif

namespace XELF.Framework {

#if XNA || WINDOWS_PHONE
	public static partial class Vector2Helper {
#else
	public partial struct Vector2 {
#endif
		/// <summary>
		/// 三角形の重心座標から直交座標の点。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="amountB"></param>
		/// <param name="amountC"></param>
		/// <param name="result"></param>
		public static void Barycentric(ref Vector2 a, ref Vector2 b, ref Vector2 c,
			float amountB, float amountC, out Vector2 result) {
			Vector2 a0, b0, c0;
			Vector2.Multiply(ref a, 1 - amountB - amountC, out a0);
			Vector2.Multiply(ref b, amountB, out b0);
			Vector2.Multiply(ref c, amountC, out c0);
			Vector2.Add(ref a0, ref b0, out result);
			Vector2.Add(ref result, ref c0, out result);
		}

		/// <summary>
		/// 3つベクトルの加重平均。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="amounts">X, Y, Z成分をa, b, cに対する重みとする</param>
		/// <param name="result"></param>
		public static void WeightedMean(ref Vector2 a, ref Vector2 b, ref Vector2 c,
			ref Vector3 amounts, out Vector2 result) {
			Vector2.Multiply(ref a, amounts.X, out result);
			Madd(ref b, amounts.Y, ref result, out result);
			Madd(ref c, amounts.Z, ref result, out result);
		}

		/// <summary>
		/// 線形補間。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="amount"></param>
		/// <param name="result"></param>
		public static void Lerp(ref Vector2 a, ref Vector2 b, float amount, out Vector2 result) {
			result = new Vector2(
				a.X + (b.X - a.X) * amount,
				a.Y + (b.Y - a.Y) * amount);
		}

		/// <summary>
		/// 双線形補間。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="d"></param>
		/// <param name="amountU"></param>
		/// <param name="amountV"></param>
		/// <param name="result"></param>
		public static void Bilinear(ref Vector2 a, ref Vector2 b, ref Vector2 c, ref Vector2 d,
			float amountU, float amountV, out Vector2 result) {
			Vector2 ab, cd;
			Lerp(ref a, ref b, amountU, out ab);
			Lerp(ref c, ref d, amountU, out cd);
			Lerp(ref ab, ref cd, amountV, out result);
		}
	}

#if XNA || WINDOWS_PHONE
	public static partial class Vector3Helper {
#else
	public partial struct Vector3 {
#endif
		/// <summary>
		/// 三角形の重心座標から直交座標の点。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="amountB"></param>
		/// <param name="amountC"></param>
		/// <param name="result"></param>
		public static void Barycentric(ref Vector3 a, ref Vector3 b, ref Vector3 c,
			float amountB, float amountC, out Vector3 result) {
			Vector3 a0, b0, c0;
			Vector3.Multiply(ref a, 1 - amountB - amountC, out a0);
			Vector3.Multiply(ref b, amountB, out b0);
			Vector3.Multiply(ref c, amountC, out c0);
			Vector3.Add(ref a0, ref b0, out result);
			Vector3.Add(ref result, ref c0, out result);
		}

		/// <summary>
		/// 3つベクトルの加重平均。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="amounts">X, Y, Z成分をa, b, cに対する重みとする</param>
		/// <param name="result"></param>
		public static void WeightedMean(ref Vector3 a, ref Vector3 b, ref Vector3 c,
			ref Vector3 amounts, out Vector3 result) {
			Vector3.Multiply(ref a, amounts.X, out result);
			Madd(ref b, amounts.Y, ref result, out result);
			Madd(ref c, amounts.Z, ref result, out result);
		}

		/// <summary>
		/// 線形補間。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="amount"></param>
		/// <param name="result"></param>
		public static void Lerp(ref Vector3 a, ref Vector3 b, float amount, out Vector3 result) {
			result = new Vector3(
				a.X + (b.X - a.X) * amount,
				a.Y + (b.Y - a.Y) * amount,
				a.Z + (b.Z - a.Z) * amount);
		}

		/// <summary>
		/// 双線形補間。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="d"></param>
		/// <param name="amountU"></param>
		/// <param name="amountV"></param>
		/// <param name="result"></param>
		public static void Bilinear(ref Vector3 a, ref Vector3 b, ref Vector3 c, ref Vector3 d,
			float amountU, float amountV, out Vector3 result) {
			Vector3 ab, cd;
			Lerp(ref a, ref b, amountU, out ab);
			Lerp(ref c, ref d, amountU, out cd);
			Lerp(ref ab, ref cd, amountV, out result);
		}
	}

#if XNA || WINDOWS_PHONE
	public static partial class Vector4Helper {
#else
	public partial struct Vector4 {
#endif
		/// <summary>
		/// 三角形の重心座標から直交座標の点。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="amountB"></param>
		/// <param name="amountC"></param>
		/// <param name="result"></param>
		public static void Barycentric(ref Vector4 a, ref Vector4 b, ref Vector4 c,
			float amountB, float amountC, out Vector4 result) {
			Vector4 a0, b0, c0;
			Vector4.Multiply(ref a, 1 - amountB - amountC, out a0);
			Vector4.Multiply(ref b, amountB, out b0);
			Vector4.Multiply(ref c, amountC, out c0);
			Vector4.Add(ref a0, ref b0, out result);
			Vector4.Add(ref result, ref c0, out result);
		}

		/// <summary>
		/// 3つベクトルの加重平均。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="amounts">X, Y, Z成分をa, b, cに対する重みとする</param>
		/// <param name="result"></param>
		public static void WeightedMean(ref Vector4 a, ref Vector4 b, ref Vector4 c,
			ref Vector3 amounts, out Vector4 result) {
			Vector4.Multiply(ref a, amounts.X, out result);
			Madd(ref b, amounts.Y, ref result, out result);
			Madd(ref c, amounts.Z, ref result, out result);
		}

		/// <summary>
		/// 線形補間。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="amount"></param>
		/// <param name="result"></param>
		public static void Lerp(ref Vector4 a, ref Vector4 b, float amount, out Vector4 result) {
			result = new Vector4(
				a.X + (b.X - a.X) * amount,
				a.Y + (b.Y - a.Y) * amount,
				a.Z + (b.Z - a.Z) * amount,
				a.W + (b.W - a.W) * amount);
		}

		/// <summary>
		/// 双線形補間。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="d"></param>
		/// <param name="amountU"></param>
		/// <param name="amountV"></param>
		/// <param name="result"></param>
		public static void Bilinear(ref Vector4 a, ref Vector4 b, ref Vector4 c, ref Vector4 d,
			float amountU, float amountV, out Vector4 result) {
			Vector4 ab, cd;
			Lerp(ref a, ref b, amountU, out ab);
			Lerp(ref c, ref d, amountU, out cd);
			Lerp(ref ab, ref cd, amountV, out result);
		}

		/// <summary>
		/// 三重線形補間。
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="d"></param>
		/// <param name="e"></param>
		/// <param name="f"></param>
		/// <param name="g"></param>
		/// <param name="h"></param>
		/// <param name="amountU"></param>
		/// <param name="amountV"></param>
		/// <param name="amountW"></param>
		/// <param name="result"></param>
		public static void Trilinear(
			ref Vector4 a, ref Vector4 b, ref Vector4 c, ref Vector4 d,
			ref Vector4 e, ref Vector4 f, ref Vector4 g, ref Vector4 h,
			ref float amountU, ref float amountV, ref float amountW, out Vector4 result) {
			Vector4 x, y;
			Bilinear(ref a, ref b, ref c, ref d, amountU, amountV, out x);
			Bilinear(ref a, ref b, ref c, ref d, amountU, amountV, out y);
			Lerp(ref x, ref b, amountW, out result);
		}
	}

}
